/**************************************************************************
 * @doc CORE
 * @module spdmodem.c | Speed Dial Modem functions 
 *
 * Product     :   SoftPay 2000 (Global Payment Methodology).
 * <nl>Developer   :  SoftPay 2000 team 
 * <nl>Notes       :
 *
 * @head3 CORE Functions |
 * @index | CORE
 * @end
 *
 * Copyright (c) 1996-2000 by VeriFone Inc. All rights reserved.
 * 
 * No part of this software may be used, stored, compiled, reproduced,
 * modified, transcribed, translated, transmitted, or transferred, in any form 
 * or by any means whether electronic, mechanical, magnetic, optical, 
 * or otherwise, without the express prior written permission of VeriFone, Inc.
 *
 * Revision History
 * ------------------------------------------------------------------------
 $Log: /SoftPay VSA2K11F/SPK2SIM/Source/Comm/spdmodem.c $
 * 
 ********************************************************************************/

#include <project.h>
#define SPD_MODEM_C

#include <ascii.h>
#include <txoinc.h>
#include <acldev.h>
#include <stdio.h>
#include <xmodem.h>
#include <applidl.h>
#include <aclconio.h>
#include <string.h>

/** /#define DEBUG_VSMODEM*/
#ifdef DEBUG_VSMODEM
#define DEBUG_95
#endif

#include <define.h>
#include <transact.h>
#include <sizes.h>
#include <init.h>
#include <msg.h>
#include <msgfuncs.h>
#include <modemmsg.h>
#include <comm.h>
#include <gds.h>
#include <tran.h>
#include <ui.h>
#include <spdebug.h>
#include <operate.h>
#include <confio.h>
#include <date.h>
#include <mem.h>
#include <menufunc.h>
#include <stats.h>
#include <modem.h>
#include <funcids.h>
#include <table.h>
#include <tct.h>

#ifdef SPDDIAL_DEFINED

#include <spdmodem.h>
#include <sdl.h>  

/********************************************************************************************* 
* @func int | inInitSpdModemCommunication | 
*        Initialise the communication object.
*
* @parm COMM_OBJECT *| obCommunication 
*       Communication object
*
* @rdesc return values.
* @flag int | VS_SUCCESS or an Error Value
* @end
**********************************************************************************************/
int inInitSpdModemCommunication(COMM_OBJECT* obCommunication) {
    MODEM_OBJECT* obModem;

    obModem = (MODEM_OBJECT *) obCommunication->Data;
    /** /pdebug(("--inInitModemComm--"));*/
    if ((obCommunication->Data = (void *) pchAlloc(sizeof(MODEM_OBJECT))) == NULL_CH)
        return(VS_ERROR);

    obModem = (MODEM_OBJECT *) obCommunication->Data;  

    obModem->fGetBlindDial = fGetCPTBlindDial;
    obModem->fGetDialType = fGetCPTDialType;
    obModem->shGetDataFormat = shGetCPTDataFormat;
    obModem->szGetPABXCode = szGetPABXCode;  

    vdInitializeSPDValidationStruct(obModem); 

    return(VS_SUCCESS);
}


/********************************************************************************************* 
* @func void |  vdInitializeSPDValidationStruct |
* Initializes the SPD validation structure.
*
* @parm MODEM_OBJECT *  | pobModem |
*
* @end
**********************************************************************************************/

typedef int (*PFI_TO_MO)(MODEM_OBJECT*);

void vdInitializeSPDValidationStruct(MODEM_OBJECT* pobModem) {
    PFI_TO_MO pinInitializeSPDValidationStruct;

    if ((pinInitializeSPDValidationStruct = inGetFunctionPointer(INIT_SPD_VALIDATION_STRUCT)) != NULL_PFI)
        pinInitializeSPDValidationStruct(pobModem);
}


/********************************************************************************************* 
* @func int |  inDefaultInitSPDValidationStruct |
* Initializes the SPD validation structure.
*
* @parm MODEM_OBJECT * | pobModem | 
*       Modem object.
*
* @end
**********************************************************************************************/

int inDefaultInitSPDValidationStruct(MODEM_OBJECT* pobModem) {
    return(VS_SUCCESS);
}

/********************************************************************************************* 
* @func int | inOpenSpdModemCommunication | 
*        Open and setup the modem.
*
* @parm COMM_OBJECT *| obCommunication 
*       Communication object
*
* @rdesc return values.
* @flag int | VS_SUCCESS or an Error Value
* @end
**********************************************************************************************/
int inOpenSpdModemCommunication(COMM_OBJECT* obCommunication) {
    MODEM_OBJECT* obModem;
    int inDataFormat;

    /** /pdebug(("--inOpenMDMCom--"));*/
    obModem = (MODEM_OBJECT *) obCommunication->Data;
    if (inLoadConfRec(CPT_FILE_NAME, SIZE_CPT_REC, obModem->inCPTIndex, (char *) &obModem->srCPT) != VS_SUCCESS) {
        vdDisplayMessageFromFile(CPT_ERROR_MSG21, ERROR_MSG);
        return(VS_ERR);
    }

    // Modem must be initialized using MODEM_OBJECT

    /*  if (inInitModemEnvironmentParam(obModem) == VS_ERR)
        {
            vdDisplayMessageFromFile( MDM_STR_ERR_MSG21, ERROR_MSG);
            return(VS_ERR);
        }
    */
    inDataFormat = obModem->shGetDataFormat(obModem->srCPT);
    //  Opens the modem port at a faster baud rate than the communicating baud rate
    if ((obModem->hModem = xmdm_init(obModem->hModem, DEV_MODEM, NO_CLOCK_HANDLE 30, BAUD_19200, inDataFormat)) < 0) {
        /** /pdebug(("xmdm_init = %d", obModem->hModem));*/
        return(VS_ERR);
    }
    return(VS_SUCCESS);
}

/********************************************************************************************* 
* @func int | inBeginSpdModemCommunication | 
*        Check whether the communication with host is successfully
*        initiated or not. The parameters required for the initialization is taken from
*        a CPT Table. The phone number to dial is passed in.
*
*               1. Assumes the CPT is loaded by the outer module.
*               2. Assumes that clock device is opened by the outer module and a
*                  handle to the clock device (hClock) is assigned properly.
*
* @parm COMM_OBJECT *| obCommunication 
*       Communication object
*
* @rdesc return values.
* @flag int | VS_SUCCESS or an Error Value
* @end
**********************************************************************************************/
int inBeginSpdModemCommunication(COMM_OBJECT* obCommunication,int inCPTIndex,VS_BOOL fUnusedParameter) {
    return (inModemSpdDial(obCommunication, inCPTIndex));
}

/********************************************************************************************* 
* @func int | inCheckSpdModemCommunication | 
*        Checks whether the communication link has been established.
*        If not displays a failure message.
*
* @parm COMM_OBJECT *| obCommunication 
*       Communication object
*
* @rdesc return values.
* @flag int | VS_SUCCESS or an Error Value
* @end
    Modification History :
      #     Date      Who                     Description
    ----- -------- ---------- ---------------------------------------------
      1   1/12/99    ANDY_W2                  Only display 'Pick Up Phone' if connection made.
**********************************************************************************************/
int inCheckSpdModemCommunication(COMM_OBJECT* obCommunication) {
    MODEM_OBJECT* obModem;
    int inMdmDialStatus,
    inRetVal = VS_ERR;
    long lnMsgNo;
    unsigned long   ulTimerCount;

    lnMsgNo = 0;
    /** /pdebug(("--inCheckModemComm--"));*/
    obModem = (MODEM_OBJECT *) obCommunication->Data;
    ulTimerCount = set_itimeout(NO_CLOCK_HANDLE 30, TM_SECONDS);
    vdDisplayMessageFromFile(RINGING_MSG21, STATUS_MSG);
    inMdmDialStatus = xmdm_dial_status(obModem->hModem, NO_CLOCK_HANDLE 5);
    vdDisplayMessageFromFile(PRESS_ENTER_MSG21, ENTRY_MSG);
    switch (inMdmDialStatus) {
    case CONNECT:
        obCommunication->fLinkUp = VS_FALSE;
        vdDisplayMessageFromFile(PICK_UP_PHONE_MSG21, ENTRY_MSG);
        break;
    case VFI_DIALDONE:
        /* VFI_DIALDONE doesn't seem to detect the end of the dial */
        break;
    case VFI_NO_LINE:
        lnMsgNo = VFI_NO_LINE_MSG21;
        break;
    case NO_DIALTONE:
        if (!(obModem->fGetBlindDial(obModem->srCPT)))
            lnMsgNo = NO_DIALTONE_MSG;
        else
            lnMsgNo = 0;
        break;
    case NO_CARRIER:
        lnMsgNo = NO_CARRIER;
        break;
    case NO_ANSWER:
    case E_HR_TIMEOUT:
        break;
    case BUSY_DETECT:
        lnMsgNo = BUSY_DETECT_MSG;
            INCREMENT_BUSY;
        break;
    case HAYES_ERROR:
    case E_READ_CMD:
    case E_ONLY_CR:
    case E_INVALID_RESP:
        lnMsgNo = COMMUNICATION_FAILURE_MSG;
    default:
        break;
    }
    if (lnMsgNo)
        vdDisplayMessageFromFile(lnMsgNo, STATUS_MSG);
    inRetVal = VS_ERR;
    do {
        /* Get out in Clear key press */
        if (KBHIT())
            switch (get_char()) {
            case KEY_CR:
                inRetVal = VS_SUCCESS;
                break;
            case KEY_CANCEL:
                inRetVal = VS_ESCAPE;
                break;
            default:
                break;
            }

        if (CHECK_TIMEOUT(ulTimerCount) == 0)
            inRetVal = VS_ESCAPE;
    } while (inRetVal == VS_ERR);
    obCommunication->inEnd(obCommunication);
    return(inRetVal);
} /* End of inCheckModemCommunication() */

/********************************************************************************************* 
* @func int | inSendSpdModemCommunication | 
*        Do nothing as this call is for voice only.
**********************************************************************************************/
int inSendSpdModemCommunication(COMM_OBJECT* obCommunication,char* pchSendBuff,int inSendSize,VS_BOOL fConfirmSend,int inTimeout,long lnMessage) {
    int inRetVal = VS_SUCCESS;
    return(inRetVal);
} /* End of inSendModemCommunication () */

/********************************************************************************************* 
* @func int | inReceiveSpdModemCommunication | 
*        Do nothing as this call is for voice only.
**********************************************************************************************/
int inReceiveSpdModemCommunication(COMM_OBJECT* obCommunication,char* pchReceiveBuff,int inReceiveSize,int inReceiveTimeout,long lnMessage) {
    int inRetVal = VS_SUCCESS;
    return(inRetVal);
} /* End of inReceiveModemCommunication () */

/********************************************************************************************* 
* @func int | inFlushSpdModemCommunication | 
*        Flushes the communication with the host. Assumption is vdConfigureModemCommunication()
*        is called at least once before closing the transmission.
*
* @rdesc return values.
* @flag int | VS_SUCCESS or an Error Value
* @end
**********************************************************************************************/
int inFlushSpdModemCommunication() {
    int inRetVal;
    MODEM_OBJECT* obModem;

    obModem = (MODEM_OBJECT *) obCommunication.Data;

    /** /pdebug(("--inFlushMDM--"));*/
    inRetVal = xmdm_flush(obModem->hModem);

    return(inRetVal);
}

/********************************************************************************************* 
* @func int | inEndSpdModemCommunication | 
*        Terminates the communication with the host. Assumption is vdConfigureModemCommunication()
*        is called at least once before closing the transmission.
*
* @parm COMM_OBJECT *| obCommunication 
*       Communication object
*
* @rdesc return values.
* @flag int | VS_SUCCESS or an Error Value
* @end
**********************************************************************************************/
int inEndSpdModemCommunication(COMM_OBJECT* obCommunication) {
    MODEM_OBJECT* obModem;
    int inCloseResult,
    inRetVal;
    unsigned long ulDC2Ticks;
    char szCommand[10];

    /** /pdebug(("--inEndMDM--"));*/
    obModem = (MODEM_OBJECT *) obCommunication->Data;
    /** /pdebug(("Hangup"));*/
    if (obModem->hModem > 0) {
        strcpy(szCommand, "H0");
        inRetVal = xhayes_send_cmd(obModem->hModem, szCommand);
        if (inRetVal != (strlen(szCommand) + XHAYES_STRING_FRAME))
            return(VS_ERR);
    }
    obCommunication->fLinkUp = VS_FALSE;
    /** /pdebug(("Done Hangup"));*/
    if (obModem->hModem <= 0)
        return(VS_SUCCESS);

    ulDC2Ticks = set_itimeout(NO_CLOCK_HANDLE 3, TM_SECONDS);
    do {
        inCloseResult = xmdm_close(obModem->hModem, 0, 0); //, 0, NULL_CH, 0);
    } while (inCloseResult == OUTPUT_PENDING && CHECK_TIMEOUT(ulDC2Ticks));

    obModem->hModem = 0;
    if (inCloseResult < 0) {
        inCloseResult = close(obModem->hModem);
        if (inCloseResult < 0) {
            /** /pdebug(("inCloseResult = %d", inCloseResult));*/
        }
    } 
    return(VS_SUCCESS);
}

/********************************************************************************************* 
* Static Func to no AutoDuc Comments.
* Dials the number gived using the CPT parameters.
**********************************************************************************************/
static int inModemSpdDial(COMM_OBJECT* obCommunication,int inCPTIndex) {
    MODEM_OBJECT* obModem;
    char szDialCommand[PHONE_NUM_SIZE + PABX_CODE_SIZE + 1 + 1];
    TRANSACTION_OBJECT* pobTran;
    char szPABXCode[PABX_CODE_SIZE + 1];
    //char szPhoneNumber[PHONE_NUM_SIZE + 1];

    int inRetVal;

    pobTran = pstGet_pobTran();
    if (pobTran == NULL)
        return VS_ERR;

    /** /pdebug(("--inModemDial--"));*/
    obModem = (MODEM_OBJECT *) obCommunication->Data;
    if (obCommunication->fLinkUp == VS_TRUE) {
        /** /pdebug (("Link UP"));*/
        return(VS_SUCCESS);
    }
    obModem->inCPTIndex = inCPTIndex;
    if (inOpenSpdModemCommunication(obCommunication) == VS_ERR) {
        /** /pdebug (("Open Error"));*/
        return(VS_ERR);
    }
    strcpy(szDialCommand, "D");
    if (obModem->fGetDialType(obModem->srCPT))
        strcat(szDialCommand, "P");     /* Do pulse dialing */
    else
        strcat(szDialCommand, "t");     /* Do tone dialing */

    strcpy(szPABXCode, obModem->szGetPABXCode());
    if (strlen(szPABXCode) > 0)
        strncat(szDialCommand, szPABXCode, PABX_CODE_SIZE);
    strcat(szDialCommand, srSDLRec.szSDLnumber);  
    /** /pdebug(("szDialCommand = %s", szDialCommand));*/
    inRetVal = xhayes_send_cmd(obModem->hModem, szDialCommand);
    if (inRetVal != (strlen(szDialCommand) + XHAYES_STRING_FRAME)) {
        /** /pdebug (("Hayes Send Error"));*/
        return(VS_ERR);
    }
    return(VS_SUCCESS);
} /* End of inModemDial () */

/********************************************************************************************* 
* @func int | inDeInitSpdModemCommunication | 
*        Terminates the communication with the host. Assumption is vdConfigureModemCommunication()
*        is called at least once before closing the transmission.
*
* @parm COMM_OBJECT *| obCommunication 
*       Communication object
*
* @rdesc return values.
* @flag int | VS_SUCCESS or an Error Value
* @end
**********************************************************************************************/
int inDeInitSpdModemCommunication(COMM_OBJECT* obCommunication) {
    MODEM_OBJECT* obModem;

    obModem = (MODEM_OBJECT *) obCommunication->Data;

    vdFree(obCommunication->Data);
    obCommunication->inLinkType = NO_COMM;

    return (VS_SUCCESS);
}

/********************************************************************************************* 
* @func void | vdInitializeSpdModemComm | 
*        Sets up the speed modem function pointers.
*
* @parm COMM_OBJECT *| obCommunication 
*       Communication object
**********************************************************************************************/
void vdInitializeSpdModemComm(COMM_OBJECT* obCommunication) {
    /** /pdebug(("--vdInitModem--"));*/
    obCommunication->inLinkType = MODEM_COMM;
    obCommunication->fLinkUp = VS_FALSE;
    obCommunication->inInitialize = inInitSpdModemCommunication;
    obCommunication->inBegin = inBeginSpdModemCommunication;
    obCommunication->inCheck = inCheckSpdModemCommunication;
    obCommunication->inSend = inSendSpdModemCommunication;
    obCommunication->inReceive = inReceiveSpdModemCommunication;
    obCommunication->inEnd = inEndSpdModemCommunication;
    obCommunication->inFlush = inFlushSpdModemCommunication;
    obCommunication->inDeinitialize = inDeInitSpdModemCommunication;
}

#undef SPD_MODEM_C

#endif  //SPDDIAL_DEFINED

